agora inbox for [email protected]help / color / mirror / Atom feed
question: data file update when pg_basebackup in progress 815+ messages / 4 participants [nested] [flat]
* question: data file update when pg_basebackup in progress @ 2017-04-25 16:08 Rui Hai Jiang <[email protected]> 0 siblings, 1 reply; 815+ messages in thread From: Rui Hai Jiang @ 2017-04-25 16:08 UTC (permalink / raw) To: pgsql-hackers Hello, I'm checking how the pg_basebackup works and I got a question(maybe there are no such issues): When pg_basebackup is launched, a checkpoint is created first, then all files are transferred to the pg_basebackup client. Is it possible that a data page(say page-N) in a data file is changed after the checkpoint and before the pg_basebackup is finished? If this happens, is it possible that only part of the changed page be transferred to the pg_basebackup client? i.e. the pg_basebackup client gets page-N with part of the old content and part of the new content. How does postgreSQL handle this kind of data page? Thanks, Rui Hai ^ permalink raw reply [nested|flat] 815+ messages in thread
* Re: question: data file update when pg_basebackup in progress @ 2017-04-25 16:45 David G. Johnston <[email protected]> parent: Rui Hai Jiang <[email protected]> 0 siblings, 1 reply; 815+ messages in thread From: David G. Johnston @ 2017-04-25 16:45 UTC (permalink / raw) To: Rui Hai Jiang <[email protected]>; +Cc: pgsql-hackers On Tue, Apr 25, 2017 at 9:08 AM, Rui Hai Jiang <[email protected]> wrote: > When pg_basebackup is launched, a checkpoint is created first, then all > files are transferred to the pg_basebackup client. Is it possible that a > data page(say page-N) in a data file is changed after the checkpoint and > before the pg_basebackup is finished? > I believe so. > If this happens, is it possible that only part of the changed page be > transferred to the pg_basebackup client? i.e. the pg_basebackup client > gets page-N with part of the old content and part of the new content. How > does postgreSQL handle this kind of data page? > The first write to a page after a checkpoint is always recorded in the WAL as a full page write. Every WAL file since the checkpoint must also be copied to the backed up system. The replay of those WAL files is what brings the remote and local system into sync with respect to all changes since the backup checkpoint. David J. ^ permalink raw reply [nested|flat] 815+ messages in thread
* Re: question: data file update when pg_basebackup in progress @ 2017-04-26 00:06 Michael Paquier <[email protected]> parent: David G. Johnston <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Michael Paquier @ 2017-04-26 00:06 UTC (permalink / raw) To: David G. Johnston <[email protected]>; +Cc: Rui Hai Jiang <[email protected]>; pgsql-hackers On Wed, Apr 26, 2017 at 1:45 AM, David G. Johnston <[email protected]> wrote: > The first write to a page after a checkpoint is always recorded in the WAL > as a full page write. Every WAL file since the checkpoint must also be > copied to the backed up system. The replay of those WAL files is what > brings the remote and local system into sync with respect to all changes > since the backup checkpoint. Bringing to the point that the presence of backup_label in a backup is critical, as this tells Postgres from which position in WAL it should begin recovery to bring the system up to a consistent state. pg_basebackup also makes sure that the last WAL segment needed is archived before the backup completes so as recovery can completely be done. -- Michael -- Sent via pgsql-hackers mailing list ([email protected]) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 815+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 815+ messages in thread
end of thread, other threads:[~2025-09-04 16:22 UTC | newest] Thread overview: 815+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2017-04-25 16:08 question: data file update when pg_basebackup in progress Rui Hai Jiang <[email protected]> 2017-04-25 16:45 ` David G. Johnston <[email protected]> 2017-04-26 00:06 ` Michael Paquier <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]>
This inbox is served by agora; see mirroring instructions for how to clone and mirror all data and code used for this inbox